package com.foryang.sudoku.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

@Controller
public class SudokuController {
    List<Integer> numList = new ArrayList<>();
    @GetMapping("/index")
    public String index(Model model){
//        int a[][]  = new int[9][9];
//        initList();
//        List<Integer> list = new ArrayList<>();
//        list.addAll(numList);
//        addNum(a,0,0, list);
//        model.addAttribute("sudokuArray",a);
//        model.addAttribute("a","1");
        return "index";
    }

    @PostMapping("/check")
    @ResponseBody
    public boolean checkArr(@RequestBody int[][] array){
        //检查当前行是否存在相同的数字
        for (int i = 0; i < array.length; i++){
            for (int j = 0; j < array[i].length; j++){
                if(!(checkRow(array[i][j], i, j, array)
                        &&checkCell(array[i][j], i, j, array)
                        &&checkBox(array[i][j], i, j, array))){
                    return false;
                }


            }
        }
        System.out.println("2");
        return true;
    }


    @ResponseBody
    @GetMapping("/get/{diff}")
    public int[][] getArray(@PathVariable Integer diff){
        int a[][]  = new int[9][9];
        if(numList.size() == 0){
            initList();
        }
        List<Integer> list = new ArrayList<>();
        list.addAll(numList);
        addNum(a,0,0, list);
        int toZeroNum = 5 + 5 * diff;
        for (int i = 0; i < toZeroNum; i++){
            createGameArr(a);
        }
        return a;
    }

    public void initList(){
        for(int num = 1; num < 10; num ++){
            numList.add(num);
        }
    }

    /**
     * 插入数字
     * @param a
     * @param x 行
     * @param y 列
     * @param list 当前还没有插入的数字列表
     * @return
     */
    public boolean addNum(int[][] a, int x, int y, List<Integer> list){
        //创建列表，存放当前列或当前小九宫格存在的数字
        List<Integer> existNum = new ArrayList<>();
        int maxSize = list.size();

        //当最后一位数成功插入后，表示该数独生成完成，不用再进行以下插入操作
        while (a[8][8] == 0){
            Random random = new Random();
            int index = random.nextInt(list.size());
            boolean flag = true;

            //判断当前列和当前小九宫格是否存在该数字，不存在则进行插入操作
            if(checkCell(list.get(index), x, y, a) && checkBox(list.get(index), x, y, a)){
                //插入数字，同时在需插入的数字列表中移除该数，避免同行出现插入相同数字的情况
                a[x][y] = list.get(index);
                list.remove(index);

                //当y=8时表示当前行已成功插入最后一位数字，则进入下一行执行插入操作
                if(y == 8){
                    List<Integer> newRow = new ArrayList<>();
                    //由于新的一行没有任何数字，则需要插入的数字为1-9，因此将初始化好的numList添加到该列表
                    newRow.addAll(numList);
                    //进入下一行进行插入操作
                    flag = addNum(a, x + 1, 0, newRow);
                } else { //当y!=8时表示该行还未添加完整，则需进入下一列执行插入操作
                    List<Integer> newCell = new ArrayList<>();
                    //除了成功插入的数字以外，其余数字都是该行后面的需插入的数字，即list中剩余的数字和existNum中表示前面不合适的所有数字
                    newCell.addAll(list);
                    newCell.addAll(existNum);
                    //进入下一列进行插入操作
                    flag = addNum(a, x, y + 1, newCell);
                }
            } else {
                //存在则添加到数字列表，同时从list移除该数，表示该数不适合在当前位置，同时避免以后为该位置插入数字时又插入相同的数字，减少运算次数
                existNum.add(list.get(index));
                list.remove(index);
            }

            //当flag为false时，表示进入下一行或下一列所有数字都不适合下一行或下一列位置，即无法成功插入
            //同时表示当前位置的数字不合适，则回退当前位置的数字，并把当前位置的数字添加到existNum中
            if(!flag){
                existNum.add(a[x][y]);
                a[x][y] = 0;
            }
            //当existNum的长度等于原列表长度时，表示所有数字都不适合当前位置
            if(existNum.size() == maxSize){
                return false;
            }
        }
        return true;
    }

    /**
     * 判断当前行有没有存在相同的数字
     * @param num 要判断的数字
     * @param x 行
     * @param y 列
     * @param a
     * @return
     */
    public boolean checkRow(int num, int x,int y, int[][] a){
        for(int i = 0; i < y; i++){
            if(num == a[x][i]){
                return false;
            }
        }
        return true;
    }

    /**
     * 判断当前列有没有存在相同的数字
     * @param num 要判断的数字
     * @param x 行
     * @param y 列
     * @param a
     * @return
     */
    public boolean checkCell(int num, int x,int y, int[][] a){
        for(int i = 0; i < x; i++){
            if(num == a[i][y]){
                //当该列存在该数字时返回false,表示已存在，不能执行插入操作
                return false;
            }
        }
        return true;
    }

    /**
     * 判断当前小九宫格是否存在相同的数字
     * @param num 要判断的数字
     * @param x 行
     * @param y 列
     * @param a
     * @return
     */
    public boolean checkBox(int num, int x,int y, int[][] a){
        //计算出当前小九宫格的初始位置
        int xBox = x / 3 * 3;
        int yBox = y / 3 * 3;

        //在当前小九宫格中，查找该数字
        for(int i = xBox; i <= xBox + 2 && i < x; i++){
            for(int j = yBox; j <= yBox + 2; j++){
                if(a[i][j] == num){
                    //当该小九宫格存在该数字时返回false,表示已存在，不能执行插入操作
                    return false;
                }
            }
        }
        return true;
    }

    public void createGameArr(int[][] a){
        Random random = new Random();
        while (true){
            int x = random.nextInt(9);
            int y = random.nextInt(9);
            if(a[x][y] != 0){
                a[x][y] = 0;
                break;
            }
        }


    }
}
